// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

import (
	"cmd/internal/src"
	"fmt"
)

// 块表示函数控制流图中的基本块。
type Block struct {
	// 块的唯一标识符。系统将尝试密集地分配
	// 这些ID，但没有保证。
	ID ID

	// 块的控制操作的源位置
	Pos src.XPos

	// 这是什么类型的块。
	Kind BlockKind

	// 分支机构的可能方向。
	// 如果是分支，Succs[0]是最有可能执行的分支。
	// 如果可能的话，Succs[1]是最有可能的分支。
	// 如果len（Succs）<2，则忽略。
	// 如果不知道和len（成功）>2，则致命。
	Likely BranchPrediction

	// 在flagalloc之后，记录块末尾的标志是否处于活动状态。
	FlagsLiveAtEnd bool

	// 后续块（如有）。数量和顺序取决于区块类型。
	Succs []Edge

	// 继任者的倒数。
	// 顺序对块中的Phi节点很重要。
	// 待办事项：保留前任是件痛苦的事。我们是否可以按块id对phi 
	// 参数进行排序，并在需要时显式计算此字段？
	Preds []Edge

	// 确定块如何退出的值列表。
	// 的数量和控制值的类型取决于块的类型。对于
	// 实例，BlockIf有一个布尔控制值，BlockExit 
	// 有一个内存控制值。
	// 
	// ControlValues（）方法可用于获取包含非零
	// 控制值的切片，控制值的范围可以超过。如果控件[0]为零，则控件[1]必须为零。
	Controls [2]*Value

	// 块的辅助信息。它的价值取决于种类。
	Aux    Aux
	AuxInt int64

	// 定义此块操作的无序值集。
	// 调度通过后，此列表被排序。
	Values []*Value

	// 包含函数
	Func *Func

	// 存储Succs、PRED和值。
	succstorage [2]Edge
	predstorage [4]Edge
	valstorage  [9]*Value
}

// 边表示CFG边。
// b分支到c或d的示例边。
// （c和d有其他前辈。）
// b.Succs=[{c，3}，{d，1}]
// c.Preds=[？，？，，？，{b，0}]
// d.Preds=[？，{b，1}，]
// 这些索引允许我们在固定时间内编辑CFG。
// 此外，它在退化的情况下通知phi操作，比如：
// b:
// if then c else c 
// c:
// v=phi（x，y）
// /然后索引告诉你x是否从
// b的if或else分支选择。
// b.Succs=[{c，0}，{c，1}]
type Edge struct {
	// 块边转到（在成功列表中）或从（在Preds列表中）
	b *Block
	// 反向边的索引。不变量：
	// e:=x.Succs[idx]
	// e.b.Preds[e.i]=Edge{x，idx}
	// 同样适用于前辈。
	i int
}

func (e Edge) Block() *Block {
	return e.b
}
func (e Edge) Index() int {
	return e.i
}
func (e Edge) String() string {
	return fmt.Sprintf("{%v,%d}", e.b, e.i)
}

// kind controls 
// --------------------------------------
// Exit[return mem][]
// Plain[][next]
// If[boolean Value][then，else]
// Defer[mem nopanic，panic]（控件操作码应该是OpStaticCall to runtime.deferproc）
type BlockKind int8

// 短格式打印
func (b *Block) String() string {
	return fmt.Sprintf("b%d", b.ID)
}

// 长格式打印
func (b *Block) LongString() string {
	s := b.Kind.String()
	if b.Aux != nil {
		s += fmt.Sprintf(" {%s}", b.Aux)
	}
	if t := b.AuxIntString(); t != "" {
		s += fmt.Sprintf(" [%s]", t)
	}
	for _, c := range b.ControlValues() {
		s += fmt.Sprintf(" %s", c)
	}
	if len(b.Succs) > 0 {
		s += " ->"
		for _, c := range b.Succs {
			s += " " + c.b.String()
		}
	}
	switch b.Likely {
	case BranchUnlikely:
		s += " (unlikely)"
	case BranchLikely:
		s += " (likely)"
	}
	return s
}

// NumControls返回
// 块具有的非零控件值的数量。
func (b *Block) NumControls() int {
	if b.Controls[0] == nil {
		return 0
	}
	if b.Controls[1] == nil {
		return 1
	}
	return 2
}

// ControlValues返回一个包含块的非零控件
// 值的切片。每个控件值的索引将是
// 与控件属性中的索引相同，并且可以在ReplaceControl调用中使用。
func (b *Block) ControlValues() []*Value {
	if b.Controls[0] == nil {
		return b.Controls[:0]
	}
	if b.Controls[1] == nil {
		return b.Controls[:1]
	}
	return b.Controls[:2]
}

// SetControl删除所有现有的控件值，然后添加
// 提供的控件值。
// 调用SetControl后的控制值数始终为1。
func (b *Block) SetControl(v *Value) {
	b.ResetControls()
	b.Controls[0] = v
	v.Uses++
}

// ResetControls将块的控件数设置为0。
func (b *Block) ResetControls() {
	if b.Controls[0] != nil {
		b.Controls[0].Uses--
	}
	if b.Controls[1] != nil {
		b.Controls[1].Uses--
	}
	b.Controls = [2]*Value{} // 将两个控件重置为零
}

// AddControl在现有控件值列表中追加一个控件值。
func (b *Block) AddControl(v *Value) {
	i := b.NumControls()
	b.Controls[i] = v // 如果数组已满，则会出现恐慌
	v.Uses++
}

// ReplaceControl在提供的索引
// 处将现有的控件值交换为新值。索引必须引用有效的控件值。
func (b *Block) ReplaceControl(i int, v *Value) {
	b.Controls[i].Uses--
	b.Controls[i] = v
	v.Uses++
}

// CopyControls将此块的控件替换为
// 提供的块中的控件。未修改提供的块。
func (b *Block) CopyControls(from *Block) {
	if b == from {
		return
	}
	b.ResetControls()
	for _, c := range from.ControlValues() {
		b.AddControl(c)
	}
}

// 重置将块设置为提供的类型，并清除所有块控制
// 和辅助值。块的其他属性，例如其后继属性
// 前导属性和值保持不变。
func (b *Block) Reset(kind BlockKind) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
}

// resetWithControl重置b并添加控件v。
// 相当于b.Reset（种类）；b、 AddControl（v），
// 除了它是一个调用而不是两个，并且避免了边界检查。
// 它用于重写规则，如果这很重要的话。
func (b *Block) resetWithControl(kind BlockKind, v *Value) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
	b.Controls[0] = v
	v.Uses++
}

// resetWithControl2重置b并添加控件v和w。
// 相当于b.Reset（种类）；b、 AddControl（v）；b、 AddControl（w），
// 除了它是一个调用，而不是三个，并且避免了两个边界检查。
// 它是为重写规则使用的，这很重要。
func (b *Block) resetWithControl2(kind BlockKind, v, w *Value) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
	b.Controls[0] = v
	b.Controls[1] = w
	v.Uses++
	w.Uses++
}

// truncateValues截断b.第i个元素的值，将后续元素归零。
// b中的值。在我必须已经重置了它们的参数之后，
// 要保持正确的值，请使用计数。
func (b *Block) truncateValues(i int) {
	tail := b.Values[i:]
	for j := range tail {
		tail[j] = nil
	}
	b.Values = b.Values[:i]
}

// AddEdgeTo在构建
// SSA图时使用，将b区的边添加到c区；不要在已经完成的SSA图上使用。
func (b *Block) AddEdgeTo(c *Block) {
	i := len(b.Succs)
	j := len(c.Preds)
	b.Succs = append(b.Succs, Edge{c, j})
	c.Preds = append(c.Preds, Edge{b, i})
	b.Func.invalidateCFG()
}

// removePred从b中删除第i个输入边。
// 调用者有责任删除
// 相应的后续边，并通过调用b.removePhiArg（v，i）来调整任何
// phi值。
func (b *Block) removePred(i int) {
	n := len(b.Preds) - 1
	if i != n {
		e := b.Preds[n]
		b.Preds[i] = e
		// 更新我们移动的边缘的另一端。
		e.b.Succs[e.i].i = i
	}
	b.Preds[n] = Edge{}
	b.Preds = b.Preds[:n]
	b.Func.invalidateCFG()
}

// removeSucc从b中删除第i个输出边缘。
// 调用者有责任删除对应的前一个边缘。
func (b *Block) removeSucc(i int) {
	n := len(b.Succs) - 1
	if i != n {
		e := b.Succs[n]
		b.Succs[i] = e
		// 更新我们移动的边缘的另一端。
		e.b.Preds[e.i].i = i
	}
	b.Succs[n] = Edge{}
	b.Succs = b.Succs[:n]
	b.Func.invalidateCFG()
}

func (b *Block) swapSuccessors() {
	if len(b.Succs) != 2 {
		b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
	}
	e0 := b.Succs[0]
	e1 := b.Succs[1]
	b.Succs[0] = e1
	b.Succs[1] = e0
	e0.b.Preds[e0.i].i = 1
	e1.b.Preds[e1.i].i = 0
	b.Likely *= -1
}

// removePhiArg从phi中删除第i个arg。
// 必须在调用b.removePred（i）到
// 调整块的相应phi值后调用：
// 
// b.removePred（i）
// for，v:=范围b.值{
// 如果v.Op！=OpPhi{
// 继续
// }
// /b.removeArg（v，i）
// }
func (b *Block) removePhiArg(phi *Value, i int) {
	n := len(b.Preds)
	if numPhiArgs := len(phi.Args); numPhiArgs-1 != n {
		b.Fatalf("inconsistent state, num predecessors: %d, num phi args: %d", n, numPhiArgs)
	}
	phi.Args[i].Uses--
	phi.Args[i] = phi.Args[n]
	phi.Args[n] = nil
	phi.Args = phi.Args[:n]
}

// LackingPos指示b是否是一个块，其位置应从其继任者继承
// 。如果其中的所有值都有不可靠的位置
// 并且是“普通”的，这是正确的，这意味着没有控制流也很可能
// 对应于一个被充分理解的源位置。
func (b *Block) LackingPos() bool {
	// 非普通前置是If或Defer，两者（1）都有两个后继者，
	// 可能有不同的行号，以及（2）对应于源代码中有位置的语句
	// 因此无论如何都不应该发生这种情况。
	if b.Kind != BlockPlain {
		return false
	}
	if b.Pos != src.NoXPos {
		return false
	}
	for _, v := range b.Values {
		if v.LackingPos() {
			continue
		}
		return false
	}
	return true
}

func (b *Block) AuxIntString() string {
	switch b.Kind.AuxIntType() {
	case "int8":
		return fmt.Sprintf("%v", int8(b.AuxInt))
	case "uint8":
		return fmt.Sprintf("%v", uint8(b.AuxInt))
	default: // 指定但未实现的类型-按int64打印
		return fmt.Sprintf("%v", b.AuxInt)
	case "": // 没有辅助int类型
		return ""
	}
}

// likelyBranch报告block b是否可能是其所有前辈的分支。
func (b *Block) likelyBranch() bool {
	if len(b.Preds) == 0 {
		return false
	}
	for _, e := range b.Preds {
		p := e.b
		if len(p.Succs) == 1 || len(p.Succs) == 2 && (p.Likely == BranchLikely && p.Succs[0].b == b ||
			p.Likely == BranchUnlikely && p.Succs[1].b == b) {
			continue
		}
		return false
	}
	return true
}

func (b *Block) Logf(msg string, args ...interface{})   { b.Func.Logf(msg, args...) }
func (b *Block) Log() bool                              { return b.Func.Log() }
func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }

type BranchPrediction int8

const (
	BranchUnlikely = BranchPrediction(-1)
	BranchUnknown  = BranchPrediction(0)
	BranchLikely   = BranchPrediction(+1)
)
